第12章 BOM

BOM,Browser Object Model 浏览器对象模型

BOM 提供了与网页无关的浏览器功能对象,其核心是 window 对象,表示浏览器的实例。因为 window 对象被复用为 ECMAScript 的 Global 对象,所以通过 var 关键字声明的所有全局变量和函数都会变成 window 对象的属性和方法。

var age = 29;
var sayAge = () => alert(this.age);
alert(window.age); // 29
sayAge(); // 29
window.sayAge();   // 29

top 对象始终指向最上层(最外层)窗口,即浏览器窗口本身;parent 对象则始终指向当前窗口的父窗口。如果当前窗口是最上层窗口,则 parent 等于 top(都等于 window);self 对象和 window 是同一个对象。这些属性都是 window 对象的属性,因此访问 window.parent、window.top 和 window.self 都可以。

window.devicePixelRatio 表示物理像素与逻辑像素之间的缩放系数

现代浏览器都支持 4 个属性:innerWidth、innerHeight、outerWidth 和 outerHeight。outerWidth 和 outerHeight 返回浏览器窗口自身的大小;innerWidth 和 innerHeight 返回浏览器窗口中页面视口的大小。

可以使用 scroll()、scrollTo() 和 scrollBy() 方法滚动页面。这 3 个方法都接收表示相对视口距离的 x 和 y 坐标,这两个参数在前两个方法中表示要滚动到的坐标,在最后一个方法中表示滚动的距离。

// 相对于当前视口向下滚动 100 像素 
window.scrollBy(0, 100);
// 相对于当前视口向右滚动 40 像素 
window.scrollBy(40, 0);
// 滚动到页面左上角 
window.scrollTo(0, 0);
// 滚动到距离屏幕左边及顶边各 100 像素的位置 
window.scrollTo(100, 100);

这几个方法也都接收一个 ScrollToOptions 字典,除了提供偏移值,还可以通过 behavior 属性告诉浏览器是否平滑滚动

// 正常滚动 
window.scrollTo({
  left: 100,
  top: 100,
  behavior: 'auto'
});
// 平滑滚动
window.scrollTo({
  left: 100,
  top: 100,
  behavior: 'smooth'
});

window.open()方法可以用于导航到指定 URL,也可以用于打开新浏览器窗口。这个方法接收 4 个参数:要加载的 URL、目标窗口、特性字符串和表示新窗口在浏览器历史记录中是否替代当前加载页面的布尔值。

// 与<a href="http://www.baidu.com" target="topFrame"/>相同
window.open("http://www.baidu.com/", "topFrame");
// 如果第二个参数不是已有窗口,则会打开一个新窗口或标签页
// 第三个参数用于指定新窗口的配置
window.open("http://www.baidu.com/","baiduWindow","height=400,width=400,top=10,left=10,resizable=yes");
// window.open()方法返回一个对新建窗口的引用
// 通过该引用,可以操作新创建的窗口
let newWin = window.open("http://www.baidu.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
// 缩放 
newWin.resizeTo(500, 800);
// 移动 
newWin.moveTo(100, 100);
// 3 秒后关闭
setTimeout(() => newWin.close(), 3000);

新创建窗口的 window 对象有一个属性 opener,指向打开它的窗口。把 opener 设置为 null 表示新打开的标签页不需要与打开它的标签页通信。如果浏览器内置的弹窗屏蔽程序阻止了弹窗,那么 window.open() 很可能会返回 null。通过以下代码判断弹窗是否被屏蔽:

let blocked = false;
try {
  let newWindow = window.open("http://www.baidu.com", "_blank");
  if (newWindow == null) {
    blocked = true;
  }
} catch (ex) {
  blocked = true;
}
if (blocked) {
  alert("弹窗被屏蔽!");
}

定时器

setTimeout() 用于指定在一定时间后执行某些代码,而 setInterval() 用于指定每隔一段时间执行某些代码。

setTimeout() 方法通常接收两个参数:要执行的代码和等待时间(毫秒)

// 在 1 秒后显示警告框
setTimeout(() => alert("Hello world!"), 1000);

调用 setTimeout() 时,会返回一个表示该排期任务的 ID,可用于取消该任务

// 设置定时任务
let timeoutId = setTimeout(() => alert("Hello world!"), 1000);
// 取消任务 
clearTimeout(timeoutId);

setInterval() 方法会定义一个循环任务,同样接收两个参数:要执行的代码和时间间隔(毫秒)

// 每隔 10 秒弹窗
setInterval(() => alert("Hello world!"), 10000);

调用 setInterval() 时,会返回一个表示该定时任务的 ID,可用于取消该任务

let num = 0, intervalId = null;
let max = 10;
let incrementNumber = function() {
  num++;
// 如果达到最大值,则取消所有未执行的任务 
  if (num == max) {
    clearInterval(intervalId);
    alert("Done"); 
  }
}
intervalId = setInterval(incrementNumber, 500);

对话框

使用 alert()、confirm() 和 prompt() 方法,可以让浏览器调用系统对话框向用户显示消息。对话框显示的时候,代码会停止执行,在它们消失以后,代码才会恢复执行。

if (confirm("Are you sure?")) {
  // 用户点击确定
  alert("I'm so glad you're sure!");
} else {
  // 用户点击取消
  alert("I'm sorry to hear you're not sure.");
}

prompt() 方法接收两个参数:要显示给用户的文本,以及文本框的默认值(可以是空字符串)。如果用户点击了确认按钮,则 prompt() 会返回文本框中的值。如果用户点击了取消按钮,或者对话框被关闭,则 prompt() 会返回 null

let result = prompt("What is your name? ", "");
if (result !== null) {
  alert("Welcome, " + result);
}

location 对象

location 对象提供了当前窗口中加载文档的信息,以及通常的导航功能,它既是 window 的属性,也是 document 的属性,也就是说,window.location 和 document.location 指向同一个对象。location 对象不仅保存着当前加载文档的信息,也保存着把 URL 解析为离散片段后能够通过属性访问的信息。

使用 location 对象的属性可以获取当前加载 URL 的具体内容,以 http://foouser:barpassword@www.wrox.com:80/WileyCDA/?q=javascript#contents 为例:

属性 说明
location.hash "#contents" URL 散列值(井号后跟零或多个字符),如果没有则为空字符串
location.host "www.wrox.com:80" 服务器名及端口号
location.hostname "www.wrox.com" 服务器名
location.href "http://www.wrox.com:80/WileyCDA/ ?q=javascript#contents" 当前加载页面的完整 URL。location 的 toString() 方法返回这个值
location.pathname "/WileyCDA/" URL 中的路径和(或)文件名
location.port "80" 请求的端口。如果 URL 中没有端口,则返回空字符串
location.protocol "http:" 页面使用的协议。通常是"http:"或"https:"
location.search "?q=javascript" URL 的查询字符串。这个字符串以问号开头
location.username "foouser" 域名前指定的用户名
location.password "barpassword" 域名前指定的密码
location.origin "#contents" URL 的源地址。只读

URLSearchParams 提供了一组标准 API 方法,通过它们可以检查和修改查询字符串。

let qs = "?q=javascript&num=10";
let searchParams = new URLSearchParams(qs);
alert(searchParams.toString());  // " q=javascript&num=10"
searchParams.has("num"); // true
searchParams.get("num"); // 10
searchParams.set("page", "3");
alert(searchParams.toString()); // " q=javascript&num=10&page=3"
searchParams.delete("q");
alert(searchParams.toString());  // " num=10&page=3"
for (let param of searchParams) {
  console.log(param);
}
// ["num", "10"]
// ["page", "3"]

通过修改 location 对象修改浏览器的地址:

// 导航到新的URL,同时在浏览器历史记录中增加一条记录
location.assign("http://www.wrox.com");
// 等同于
window.location = "http://www.wrox.com";
location.href = "http://www.wrox.com"; // 最常见

修改 location 对象其他参数也会导致页面重新加载,并且在浏览器历史记录中会增加相应记录。如果不希望增加历史记录,可以使用 replace() 方法。这个方法接收一个 URL 参数,但页面重新加载后,浏览器的后退按钮是无法回到上一个页面的。

通过 reload() 方法可以重新加载当前页面:

location.reload(); // 重新加载,可能是从缓存加载 
location.reload(true); // 重新加载,从服务器加载

脚本中位于 reload() 调用之后的代码可能执行也可能不执行,这取决于网络延迟和系统资源等因素。为此,最好把 reload()作为最后一行代码。

navigator 对象

navigator 对象的属性通常用于确定浏览器的类型。

检测插件:

// 插件检测,IE10 及更低版本无效
let hasPlugin = function(name) {
  name = name.toLowerCase();
  for (let plugin of window.navigator.plugins) {
    if (plugin.name.toLowerCase().indexOf(name) > -1) {
      return true;
    }
  }
  return false;
}
// 检测Flash 
alert(hasPlugin("Flash"));
// 检测QuickTime 
alert(hasPlugin("QuickTime"));

// 在旧版本 IE 中检测插件
function hasIEPlugin(name) {
  try {
    new ActiveXObject(name);
    return true;
  } catch (ex) {
    return false;
  }
}
// 检测Flash 
alert(hasIEPlugin("ShockwaveFlash.ShockwaveFlash"));
// 检测QuickTime 
alert(hasIEPlugin("QuickTime.QuickTime"));

// 在所有浏览器中检测Flash 
function hasFlash() {
  var result = hasPlugin("Flash");
  if (!result){
    result = hasIEPlugin("ShockwaveFlash.ShockwaveFlash");
  }
  return result;
}
// 在所有浏览器中检测QuickTime 
function hasQuickTime() {
  var result = hasPlugin("QuickTime");
  if (!result){
    result = hasIEPlugin("QuickTime.QuickTime");
  }
  return result;

}
// 检测Flash 
alert(hasFlash());
// 检测QuickTime 
alert(hasQuickTime());

screen对象

screen 对象在实际编程中很少用到,暂时略过,如后期有合适的例子再进行补充

history 对象

history 对象表示当前窗口首次使用以来用户的导航历史记录,但是出于安全的考虑,该对象并不会暴露用户访问过的 URL,但是可以进行前进和后退。

go() 方法可以在用户历史记录中前进或者后退,方法接收一个整数参数,表示前进或后退多少步。

// 后退一页 
history.go(-1);
// 前进一页 
history.go(1);
// 前进两页 
history.go(2);
// 刷新当前页
history.go(0);

go() 还有两个简写方法:back() 和 forward(),分别用来后退和前进一步。

history 对象有一个 length 属性,表示历史记录中有多少条记录。